# -*- coding: utf-8 -*-
import mod.server.extraServerApi as serverApi
from mod.server.system.serverSystem import ServerSystem

from dwjjCoreServerScripts.common import consts, logger
from dwjjCoreServerScripts.util import textUtil


class PlayerModule(object):
    # 登录时的固定位置
    loginPos = None
    # 方块交互的冷却间隔 配置
    useBlockCooldownDict = dict()
    # 方块交互冷区中的坐标
    # (dim, x, y, z)
    useBlockCooldownPos = set()
    # 禁止使用的物品列表
    itemBanList = set()
    # 鞘翅飞行时使用烟花的冷却间隔
    elytraFireworkCooldown = 0
    # 鞘翅飞行时使用烟花 冷却中的玩家列表
    elytraFireworkCooldownPlayerIdList = set()
    # 玩家禁止前往的维度
    playerDenyToDimSet = set()

    def __init__(self, serverSystem, config):
        # type: (ServerSystem, dict) -> None
        self.serverSystem = serverSystem
        self.config = config
        # 判断该系统是否启用
        if not config["enable"]:
            self.enable = False
            return
        # 初始化引擎工厂
        self.InitComp()
        # 初始化基础参数
        self.InitSetting()
        # 注册监听器
        self.InitListener()

    def InitComp(self):
        self.blockUseEventWhiteList = serverApi.GetEngineCompFactory().CreateBlockUseEventWhiteList(
            serverApi.GetLevelId())
        self.gameComp = serverApi.GetEngineCompFactory().CreateGame(serverApi.GetLevelId())

    def InitSetting(self):
        # 玩家固定上线位置
        loginLocDict = self.config["loginPos"]
        if loginLocDict["enable"]:
            self.loginPos = loginLocDict["pos"]
        # 方块交互间隔时间
        for k, v in self.config["blockUseCooldown"].items():
            blockName = k.encode("utf-8")
            self.useBlockCooldownDict[blockName] = v
            self.blockUseEventWhiteList.AddBlockItemListenForUseEvent(blockName + ":*")
        # 禁止使用的物品
        for v in self.config["itemBanList"]:
            self.itemBanList.add(v.encode("utf-8"))
        # 飞行时使用烟花的冷却间隔
        self.elytraFireworkCooldown = self.config["elytraFireworkCooldown"]
        # 玩家禁止通过传送门前往的维度
        for v in self.config.get("playerDenyToDim"):
            self.playerDenyToDimSet.add(v)

    def InitListener(self):
        # 客户端配置请求
        self.serverSystem.ListenForEvent(consts.ClientModName, consts.ClientSystemName, consts.PlayerModuleConfigRequest, self, self.OnConfigRequest, 0)
        # 创建玩家实体对象事件  可修改玩家登录位置
        self.serverSystem.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerPlayerBornPosEvent", self, self.OnServerPlayerBornPosEvent, 0)
        # 使用方块事件
        self.serverSystem.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerBlockUseEvent", self, self.OnBlockUse, 0)
        # 玩家上线消息
        self.playerJoinQuitMessage = self.config["playerJoinQuitMessage"]
        if self.playerJoinQuitMessage["enable"]:
            self.serverSystem.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "PlayerJoinMessageEvent", self, self.OnPlayerJoinMessage, 5)
            self.serverSystem.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "PlayerLeftMessageServerEvent", self, self.OnPlayerQuitMessage, 5)
        # 鞘翅飞行状态下 使用烟花火箭的检测
        self.serverSystem.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerItemTryUseEvent", self, self.OnGlidingUseFirework, 0)
        # 玩家禁止前往的维度
        self.serverSystem.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "WillTeleportToServerEvent", self, self.OnPlayerPortal, 0)

    # 客户端配置请求
    def OnConfigRequest(self, e):
        responseDict = {
            "itemBanList": list(self.itemBanList),
            "elytraFireworkCooldown": self.elytraFireworkCooldown
        }
        self.serverSystem.NotifyToClient(e["playerId"], consts.PlayerModuleConfigResponse, responseDict)

    # 玩家在触发登录事件前优先触发该事件
    # 该事件为 创建玩家对象过程
    # 可修改玩家的坐标信息
    def OnServerPlayerBornPosEvent(self, e):
        if self.loginPos is not None:
            e["dimensionId"] = self.loginPos[0]
            e["posx"] = self.loginPos[1]
            e["posy"] = self.loginPos[2]
            e["posz"] = self.loginPos[3]
            e["rotx"] = self.loginPos[4]
            e["roty"] = self.loginPos[5]
            e["ret"] = True

    # 方块交互的冷却间隔
    def OnBlockUse(self, e):
        pos = (e["dimensionId"], e["x"], e["y"], e["z"])
        if pos in self.useBlockCooldownPos:
            e["cancel"] = True
            return

        blockName = e["blockName"]
        if blockName in self.useBlockCooldownDict:
            # 获取冷却秒数
            cooldown = self.useBlockCooldownDict[blockName]
            self.useBlockCooldownPos.add(pos)
            self.gameComp.AddTimer(cooldown, self.RemoveCooldownPos, pos=pos)

    # 从冷却列表删除间隔
    def RemoveCooldownPos(self, pos):
        self.useBlockCooldownPos.remove(pos)

    # 玩家加入消息
    def OnPlayerJoinMessage(self, e):
        e["message"] = textUtil.TextColor(str(self.playerJoinQuitMessage["join"]["message"]).replace("%player%", e["name"]))
        e["cancel"] = self.playerJoinQuitMessage["join"]["cancel"]

    # 玩家退出消息
    def OnPlayerQuitMessage(self, e):
        e["message"] = textUtil.TextColor(str(self.playerJoinQuitMessage["quit"]["message"]).replace("%player%", e["name"]))
        e["cancel"] = self.playerJoinQuitMessage["quit"]["cancel"]

    # 玩家在鞘翅飞行过程中使用烟花火箭的限制
    def OnGlidingUseFirework(self, e):
        if self.elytraFireworkCooldown > 0:
            itemDict = e["itemDict"]
            itemName = itemDict["newItemName"]
            playerId = e["playerId"]
            if itemName == "minecraft:firework_rocket":
                # 如果玩家正在冷却列表中 则阻止
                if playerId in self.elytraFireworkCooldownPlayerIdList:
                    e["cancel"] = True
                # 否则加入冷却列表
                else:
                    self.elytraFireworkCooldownPlayerIdList.add(playerId)
                    self.gameComp.AddTimer(self.elytraFireworkCooldown, self.RemoveElytraFireworkCooldownPlayerId, playerId=playerId)

    def RemoveElytraFireworkCooldownPlayerId(self, playerId):
        self.elytraFireworkCooldownPlayerIdList.remove(playerId)

    # 玩家禁止前往的维度
    def OnPlayerPortal(self, e):
        if e["toDimensionId"] in self.playerDenyToDimSet:
            e["cancel"] = True


